package com.hsc.www.plugin.dataPermission;

import com.hsc.www.plugin.PageHelper;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SubSelect;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class PermissionHelper implements Interceptor {
    private Logger log = LoggerFactory.getLogger(PageHelper.class);
    static int MAPPED_STATEMENT_INDEX = 0;// 这是对应上面的args的序号
    static int PARAMETER_INDEX = 1;
    static int ROWBOUNDS_INDEX = 2;
    static int RESULT_HANDLER_INDEX = 3;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        Object target = invocation.getTarget(); //被代理对象
        Method method = invocation.getMethod(); //代理方法
        Object[] args = invocation.getArgs(); //方法参数


        final Object[] queryArgs = invocation.getArgs();
        final MappedStatement mappedStatement = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
        final Object parameter = queryArgs[PARAMETER_INDEX];
        final BoundSql boundSql = mappedStatement.getBoundSql(parameter);

        String sql = boundSql.getSql();

        PermissionRule permissionRule = new PermissionRule();
        permissionRule.setTableName("student");
        permissionRule.setRole("user");
        permissionRule.setExps("id = {uid}");
        List<PermissionRule> lit = new ArrayList<>();
        lit.add(permissionRule);

        SQLPrincipal principal = new SQLPrincipalImpl();
        principal.setId("123456");
        principal.setRoleList(Arrays.asList("user"));


        processSelectSql(sql, lit, principal);
        return null;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }


    public static String processSelectSql(String sql, List<PermissionRule> rules, SQLPrincipal principal) {


        try {
            String replaceSql = null;
            Select select = (Select) CCJSqlParserUtil.parse(sql);
            PlainSelect selectBody = (PlainSelect) select.getSelectBody();
            String mainTable = null;
            if (selectBody.getFromItem() instanceof Table) {
                mainTable = ((Table) selectBody.getFromItem()).getName().replace("`", "");
            } else if (selectBody.getFromItem() instanceof SubSelect) {
                replaceSql = processSelectSql(((SubSelect) selectBody.getFromItem()).getSelectBody().toString(), rules, principal);
            }

            if (replaceSql != null && !"".equals(replaceSql.trim())) {
                sql = sql.replace(((SubSelect) selectBody.getFromItem()).getSelectBody().toString(), replaceSql);
            }
            String mainTableAlias = mainTable;
            try {
                mainTableAlias = selectBody.getFromItem().getAlias().getName();
            } catch (Exception e) {
//                log.debug("当前sql中， " + mainTable + " 没有设置别名");
            }
            String condExpr = null;
            PermissionRule realRuls = null;
            for (PermissionRule rule : rules) {
                for (String role : principal.getRoleList()) {
                    if (rule.getRole().equals(role) && rule.getTableName().equalsIgnoreCase(mainTable)) {

                        // 若主表匹配规则主体，则直接使用本规则
                        realRuls = rule;
                        condExpr = rule.getExps().replace("{uid}", principal.getId()).replace("{me}", mainTable).replace("{me.a}", mainTableAlias);
                        if (selectBody.getWhere() == null) {
                            selectBody.setWhere(CCJSqlParserUtil.parseCondExpression(condExpr));
                        } else {
                            AndExpression and = new AndExpression(selectBody.getWhere(), CCJSqlParserUtil.parseCondExpression(condExpr));
                            selectBody.setWhere(and);
                        }
                    }
                }
            }
            if (realRuls == null) return sql; // 没有合适规则直接退出。
            if (sql.indexOf("limit ?,?") != -1 && select.toString().indexOf("LIMIT ? OFFSET ?") != -1) {
                sql = select.toString().replace("LIMIT ? OFFSET ?", "limit ?,?");
            } else {
                sql = select.toString();
            }
        } catch (JSQLParserException e) {
//            log.error("change sql error .", e);
        }
        return sql;
    }


}
